package com.siyu.predict.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.siyu.basedata.modelparam.domain.ModelParam;
import com.siyu.basedata.modelparam.service.IModelParamService;
import com.siyu.basedata.plan.domain.Plan;
import com.siyu.basedata.plan.service.IPlanService;
import com.siyu.basedata.pptnrsence.domain.PptnRSence;
import com.siyu.basedata.pptnrsence.service.IPptnRSenceService;
import com.siyu.basedata.rainsence.domain.RainSence;
import com.siyu.basedata.rainsence.service.IRainSenceService;
import com.siyu.basedata.rsvrrlaste.domain.RsvrRLaste;
import com.siyu.basedata.rsvrrlaste.service.IRsvrRLasteService;
import com.siyu.basedata.wrprsrbsin.domain.WrpRsrBsin;
import com.siyu.basedata.wrprsrbsin.service.IWrpRsrBsinService;
import com.siyu.basedata.wrprsrhych.domain.WrpRsrHych;
import com.siyu.basedata.wrprsrhych.service.IWrpRsrHychService;
import com.siyu.basedata.xajresult.domain.XajResult;
import com.siyu.basedata.xajresult.service.IXajResultService;
import com.siyu.common.core.domain.AjaxResult;
import com.siyu.common.utils.WordReport;
import com.siyu.common.utils.uuid.IdUtils;
import com.siyu.model.xajmodel.XajData;
import com.siyu.model.xajmodel.XajModel;
import com.siyu.predict.dto.*;
import com.siyu.predict.service.PredictService;
import com.siyu.predict.utils.AlgorithmUtil;
import com.siyu.predict.utils.DataServiceUtil;
import com.siyu.predict.utils.DataUtil;
import com.siyu.predict.vo.DrpVo;
import com.siyu.prewarn.service.IPrewarnService;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.object.SqlQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class PredictServiceImpl implements PredictService {
    @Autowired
    private IXajResultService xajResultService;
    @Autowired
    private IPlanService planService;
    @Autowired
    private IRsvrRLasteService rsvrRLasteService;
    @Autowired
    private IModelParamService modelParamService;
    @Autowired
    private IWrpRsrBsinService rsrBsinService;
    @Autowired
    private IWrpRsrHychService wrpRsrHychService;
    @Autowired
    private IRainSenceService rainSenceService;
    @Autowired
    private IPptnRSenceService pptnRSenceService;
    @Autowired
    private IPrewarnService prewarnService;

    @Autowired
    private IWrpRsrBsinService wrpRsrBsinService;

    @Autowired
    private RedisTemplate<String, String> caiyunredisTemplate;


    @Override
    @Transactional
    public void saveRainsence(RainSenceDto rainSenceDto) {
        try {
            String id = IdUtils.getId();
            RainSence rainSence = new RainSence().builder().id(id).rscd(rainSenceDto.getRscd())
                    .senceName(rainSenceDto.getSenceName())
                    .senceDetail(rainSenceDto.getSenceDetail())
                    .createTime(new Date()).preType(rainSenceDto.getPreType()).build();
            List<PptnRSence> pptnRSences = rainSenceDto.getDatas();
            rainSenceService.insertRainSence(rainSence);
            for (PptnRSence pptnRSence : pptnRSences) {
                pptnRSence.setId(IdUtils.getId());
                pptnRSence.setSenceId(id);
            }
            pptnRSenceService.saveBatch(pptnRSences);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Map<Object, Object> getPlanDetail(String id) {
        try {
            HashMap<Object, Object> map = new HashMap<>();
            QueryWrapper<XajResult> xajResultQueryWrapper = new QueryWrapper<>();
            xajResultQueryWrapper.select("id", "tm", "pre_q", "pre_z", "check_q", "net_rain", "area_rain")
                    .eq("plan_id", id).orderByAsc("tm");
            List<XajResult> list = xajResultService.list(xajResultQueryWrapper);
            map.put("xajData", list);
            Plan plan = planService.getById(id);
            // 统计预报信息
            Map<String, Object> resultMap = DataUtil.getTotalDetail(list);
            resultMap.put("runoffNum", NumberUtil.round(plan.getRunoffNum(), 2));
            // 累计降雨量
            map.put("counts", resultMap);
            if (!plan.getPlanType().equals("假拟")) {
                // 查询水库的实测水位和实测入库流量
//                QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
//                rsvrRLasteQueryWrapper.select("id", "rz", "inq", "tm")
//                        .eq("stcd", plan.getRscd())
//                        .ge("tm", plan.getStartTime())
//                        .le("tm", plan.getEndTime())
//                        .apply("date_trunc('hour', tm) = tm")
//                        .orderByAsc("tm");
//                List<RsvrRLaste> rsvrData = rsvrRLasteService.list(rsvrRLasteQueryWrapper);
                List<RsvrRLaste> rsvrData = DataServiceUtil.getRsvrVoList(plan.getRscd(), plan.getStartTime(), plan.getEndTime(), 1);
                map.put("rsvrData", rsvrData);
            }
            return map;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    @Transactional
    public void saveManualPlan(PlanDto planDto) {
        try {
            Plan plan = new Plan();
            // 保存方案
            BeanUtil.copyProperties(planDto, plan);
            String planId = IdUtils.getId();
            plan.setId(planId);
            plan.setCalcType("手动计算");
            plan.setPreType("预报");
            plan.setCreateTime(new Date());
            //  nash系数计算
            if (planDto.getPlanType().equals("历史")) {
                // 查询实测数据
                QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
                rsvrRLasteQueryWrapper.eq("stcd", planDto.getRscd())
                        .ge("tm", planDto.getStartTime())
                        .le("tm", planDto.getEndTime())
                        .apply("date_trunc('hour', tm) = tm")
                        .orderByAsc("tm");

                List<Double> relQ = rsvrRLasteService.list(rsvrRLasteQueryWrapper)
                        .stream()
                        .map(RsvrRLaste::getInq)
                        .collect(Collectors.toList());

                List<Double> preQ = planDto.getXajData()
                        .stream()
                        .map(XajResult::getPreQ)
                        .collect(Collectors.toList());
                Double nash = AlgorithmUtil.calcNash(preQ, relQ);
                plan.setNash(nash);
            }
            planService.save(plan);
            // 保存预报结果
            List<XajResult> list = planDto.getXajData().stream()
                    .map(xajResult -> {
                        xajResult.setPlanId(planId);
                        xajResult.setId(IdUtils.getId());
                        return xajResult;
                    })
                    .collect(Collectors.toList());
            xajResultService.saveBatch(list);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    @Override
    public Map<Object, Object> getDrpData(PlanDto planDto) throws Exception {
        // 获取面雨量
//        HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(planDto.getRscd(), planDto.getStartTime(), planDto.getEndTime(), planDto.getStep());
        HashMap<Object, Object> areaRainfall = DataServiceUtil.getDrpVoList(planDto.getRscd(), planDto.getStartTime(), planDto.getEndTime(), 1);
        // 获取累计雨量
        List<Double> prList = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        List<Double> totalRain = new ArrayList<>();
        Double sum = 0.0;
        for (Double value : prList) {
            sum += value;
            totalRain.add(NumberUtil.round(sum, 1).doubleValue());
        }
        areaRainfall.put("totalRain", totalRain);
        double allRain = prList.stream()
                .mapToDouble(Double::doubleValue)
                .sum();
        long nonZeroCount = prList.stream()
                .filter(value -> value != 0)
                .count();
        areaRainfall.put("allRain", NumberUtil.round(allRain, 1).doubleValue());
        areaRainfall.put("rainTm", nonZeroCount);
        return areaRainfall;
    }

    @Override
    public Map<Object, Object> getpreDrpData(PlanDto planDto) throws Exception {
        // 获取面雨量
        HashMap<Object, Object> areaRainfall = DataUtil.getpreAreaRainfall(planDto.getRscd(), planDto.getStartTime(), planDto.getEndTime(), planDto.getStep());
        // 获取累计雨量
        List<Double> prList = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        List<Double> totalRain = new ArrayList<>();
        Double sum = 0.0;
        for (Double value : prList) {
            sum += value;
            totalRain.add(NumberUtil.round(sum, 1).doubleValue());
        }
        areaRainfall.put("totalRain", totalRain);
        double allRain = prList.stream()
                .mapToDouble(Double::doubleValue)
                .sum();
        long nonZeroCount = prList.stream()
                .filter(value -> value != 0)
                .count();
        areaRainfall.put("allRain", NumberUtil.round(allRain, 1).doubleValue());
        areaRainfall.put("rainTm", NumberUtil.round(nonZeroCount, 1).doubleValue());
        return areaRainfall;
    }

    @Override
    public Map<Object, Object> hisCalc(HisCalcDto hisCalcDto) throws Exception {
        // 获取面雨量
//        HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(hisCalcDto.getRscd(), hisCalcDto.getStartTime(), hisCalcDto.getEndTime(), hisCalcDto.getStep());
        HashMap<Object, Object> areaRainfall = DataServiceUtil.getDrpVoList(hisCalcDto.getRscd(), DateUtil.offsetDay(hisCalcDto.getStartTime(), -3), hisCalcDto.getEndTime(), hisCalcDto.getStep());
        List<Double> areaRain = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        if (areaRain.size() == 0) {
            throw new Exception("暂无此时间段数据！");
        }
        // 蒸发序列
        List<Double> erList = IntStream.range(0, areaRain.size()).mapToObj(i -> 0.0).collect(Collectors.toList());
        // 获取模型参数
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.eq("model_mark", "xaj").eq("rscd", hisCalcDto.getRscd());
        Map<String, Double> map = modelParamService.list(modelParamQueryWrapper).stream()
                .collect(Collectors.toMap(ModelParam::getParamNum, ModelParam::getParamDefault, (oldValue, newValue) -> oldValue, HashMap::new));
        // 面积查询
        QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
        wrpRsrHychQueryWrapper.eq("rscd", hisCalcDto.getRscd());
        WrpRsrHych wrpRsrHych = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper);
        XajData xajData = new XajData(areaRain, erList, hisCalcDto.getStep(), wrpRsrHych.getCnctar(), map);
        // 开始新安江模型计算
        Map<Object, Object> calc = XajModel.calc(xajData);
        // 获取模型计算结果
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(hisCalcDto.getStartTime());
        List<Double> spreQ = Convert.toList(Double.class, calc.get("preQ")); // 预报流量
        List<Double> snetRain = Convert.toList(Double.class, calc.get("netRain")); // 净雨量
        List<String> stms = Convert.toList(String.class, areaRainfall.get("tms")); // 时间序列

        // 使用流操作找到 startTime 的下标
        int startIndex = IntStream.range(0, stms.size())
                .filter(i -> stms.get(i).equals(startTime))
                .findFirst()
                .orElse(-1);

        // 检查 startIndex 是否有效
        if (startIndex == -1) {
            System.out.println("startTime not found in tms.");
            throw new Exception("查询异常！");
        }
        // 使用流操作提取从 startIndex 开始的子列表
        List<Double> preQ = IntStream.range(startIndex, spreQ.size())
                .mapToObj(spreQ::get)
                .collect(Collectors.toList());

        List<Double> netRain = IntStream.range(startIndex, snetRain.size())
                .mapToObj(snetRain::get)
                .collect(Collectors.toList());

        List<String> tms = IntStream.range(startIndex, stms.size())
                .mapToObj(stms::get)
                .collect(Collectors.toList());

        List<Double> newareaRain = IntStream.range(startIndex, areaRain.size())
                .mapToObj(areaRain::get)
                .collect(Collectors.toList());
        // 预报水位
        List<Double> regulate = DataUtil.regulate(preQ, tms, hisCalcDto.getRscd());
        List<Double> preZ = DataUtil.waterBalance(preQ, regulate, tms, hisCalcDto.getRscd());
        // 校正流量
        List<Double> checkQ = DataUtil.check(1, tms, preQ, hisCalcDto.getRscd());

        List<XajResult> xajResults = new ArrayList<>();
        // 数据结果处理
        for (int i = 0; i < newareaRain.size(); i++) {
            XajResult xajResult = new XajResult();
            xajResult.setTm(tms.get(i));
            xajResult.setPreQ(preQ.get(i));
            xajResult.setNetRain(netRain.get(i));
            xajResult.setAreaRain(newareaRain.get(i));
            // TODO: 2024/6/16 需要替换为真实的预测水位和校正流量
//            xajResult.setPreZ(23.1);
//            xajResult.setCheckQ(NumberUtil.round(preQ.get(i)+Math.random(),2).doubleValue());
            xajResult.setPreZ(preZ.get(i));
            xajResult.setCheckQ(checkQ.get(i));

            xajResults.add(xajResult);
        }
        HashMap<Object, Object> returnMap = new HashMap<>();
        // 新安江模型计算结果
        returnMap.put("xajData", xajResults);
        // 统计预报信息
        Map<String, Object> totalDetail = DataUtil.getTotalDetail(xajResults);
        totalDetail.put("runoffNum", NumberUtil.round(Double.valueOf(calc.get("runoffNum").toString()), 2));
        returnMap.put("counts", totalDetail);
        // 查询水库的实测水位和实测入库流量
//        QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
//        rsvrRLasteQueryWrapper.select("id", "rz", "inq", "tm")
//                .eq("stcd", hisCalcDto.getRscd())
//                .ge("tm", hisCalcDto.getStartTime())
//                .le("tm", hisCalcDto.getEndTime())
//                .apply("date_trunc('hour', tm) = tm")
//                .orderByAsc("tm");
//        List<RsvrRLaste> rsvrData = rsvrRLasteService.list(rsvrRLasteQueryWrapper);
        List<RsvrRLaste> rsvrData = DataServiceUtil.getRsvrVoList(hisCalcDto.getRscd(), hisCalcDto.getStartTime(), hisCalcDto.getEndTime(), 1);
        returnMap.put("rsvrData", rsvrData);
        return returnMap;
    }

    @Override
    public Map<Object, Object> relCalc(RelCalcDto relCalcDto) throws Exception {
        // 获取当前时间
        Date startTime = DateUtil.parse(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:00:00")).toJdkDate();
        // 获取预热期开始时间
//        DateTime prestartTime = DateUtil.offsetHour(startTime, -relCalcDto.getPrePeriod());
        // 获取计算结束时间
        DateTime endTime = DateUtil.offsetHour(startTime, relCalcDto.getPreinterval());
        // 获取面雨量
        HashMap<Object, Object> areaRainfall = DataUtil.getpreAreaRainfall(relCalcDto.getRscd(), DateUtil.offsetDay(startTime, -3), endTime, relCalcDto.getStep());
        List<Double> areaRain = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        // 蒸发序列
        List<Double> erList = IntStream.range(0, areaRain.size()).mapToObj(i -> 0.0).collect(Collectors.toList());
        // 获取模型参数
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.eq("model_mark", "xaj").eq("rscd", relCalcDto.getRscd());
        Map<String, Double> map = modelParamService.list(modelParamQueryWrapper).stream()
                .collect(Collectors.toMap(ModelParam::getParamNum, ModelParam::getParamDefault, (oldValue, newValue) -> oldValue, HashMap::new));
        // 面积查询
        QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
        wrpRsrHychQueryWrapper.eq("rscd", relCalcDto.getRscd());
        WrpRsrHych wrpRsrHych = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper);
        XajData xajData = new XajData(areaRain, erList, relCalcDto.getStep(), wrpRsrHych.getCnctar(), map);
        // 开始新安江模型计算
        Map<Object, Object> calc = XajModel.calc(xajData);
        // 获取模型计算结果
        String startTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTime);
        List<Double> spreQ = Convert.toList(Double.class, calc.get("preQ")); // 预报流量
        List<Double> snetRain = Convert.toList(Double.class, calc.get("netRain")); // 净雨量
        List<String> stms = Convert.toList(String.class, areaRainfall.get("tms")); // 时间序列
        // 使用流操作找到 startTime 的下标
        int startIndex = IntStream.range(0, stms.size())
                .filter(i -> stms.get(i).equals(startTime2))
                .findFirst()
                .orElse(-1);

        // 检查 startIndex 是否有效
        if (startIndex == -1) {
            throw new Exception("查询异常！");
        }
        // 使用流操作提取从 startIndex 开始的子列表
        List<Double> preQ = IntStream.range(startIndex, spreQ.size())
                .mapToObj(spreQ::get)
                .collect(Collectors.toList());

        List<Double> netRain = IntStream.range(startIndex, snetRain.size())
                .mapToObj(snetRain::get)
                .collect(Collectors.toList());

        List<String> tms = IntStream.range(startIndex, stms.size())
                .mapToObj(stms::get)
                .collect(Collectors.toList());

        List<Double> newareaRain = IntStream.range(startIndex, areaRain.size())
                .mapToObj(areaRain::get)
                .collect(Collectors.toList());

        if (preQ.size() != netRain.size() || preQ.size() != tms.size() || netRain.size() != tms.size())
            throw new Exception("计算数据异常！");
        List<XajResult> xajResults = new ArrayList<>();
        // TODO: 2024/6/17 步长不为1的时候会有bug，需要处理

//        int firstIndex = tms.indexOf(DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"));
        // 预报水位
        List<Double> regulate = DataUtil.regulate(preQ, tms, relCalcDto.getRscd());
        List<Double> preZ = DataUtil.waterBalance(preQ, regulate, tms, relCalcDto.getRscd());
        // 数据结果处理
        for (int i = 0; i < newareaRain.size(); i++) {
            XajResult xajResult = new XajResult();
            xajResult.setTm(tms.get(i));
            xajResult.setPreQ(preQ.get(i));
            xajResult.setNetRain(netRain.get(i));
            xajResult.setAreaRain(newareaRain.get(i));
            // TODO: 2024/6/16 需要替换为真实的预测水位和校正流量
//            xajResult.setPreZ(23.1);
            xajResult.setPreZ(preZ.get(i));
//            xajResult.setCheckQ(NumberUtil.round(preQ.get(i)+Math.random(),2).doubleValue());
            xajResults.add(xajResult);
        }
        HashMap<Object, Object> returnMap = new HashMap<>();
        // 新安江模型计算结果
        returnMap.put("xajData", xajResults);
        // 统计预报信息
        Map<String, Object> totalDetail = DataUtil.getTotalDetail(xajResults);
        totalDetail.put("runoffNum", NumberUtil.round(Double.valueOf(calc.get("runoffNum").toString()), 2));
        returnMap.put("counts", totalDetail);
        // 查询水库的实测水位和实测入库流量
//        QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
//        rsvrRLasteQueryWrapper.select("id", "rz", "inq", "tm")
//                .eq("stcd", relCalcDto.getRscd())
//                .ge("tm", startTime)
//                .le("tm", endTime)
//                .apply("date_trunc('hour', tm) = tm")
//                .orderByAsc("tm");
//        List<RsvrRLaste> rsvrData = rsvrRLasteService.list(rsvrRLasteQueryWrapper);
//        returnMap.put("rsvrData", rsvrData);
        returnMap.put("startTime", startTime);
        returnMap.put("endTime", endTime);
        return returnMap;
    }

    @Override
    public Map<Object, Object> hypCalc(HypCalcDto hypCalcDto) throws Exception {
        // 雨量序列
        List<Double> prList = hypCalcDto.getPr();
        // 蒸发序列
        List<Double> erList = IntStream.range(0, hypCalcDto.getPr().size()).mapToObj(i -> Math.random() * 0.05).collect(Collectors.toList());
        // 新安江模型参数查询
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.eq("model_mark", "xaj").eq("rscd", hypCalcDto.getRscd());
        Map<String, Double> map = modelParamService.list(modelParamQueryWrapper).stream()
                .collect(Collectors.toMap(ModelParam::getParamNum, ModelParam::getParamDefault, (oldValue, newValue) -> oldValue, HashMap::new));
        // 面积查询
        QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
        wrpRsrHychQueryWrapper.eq("rscd", hypCalcDto.getRscd());
        WrpRsrHych wrpRsrHych = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper);
        XajData xajData = new XajData(prList, erList, 1, wrpRsrHych.getCnctar(), map);
        // 开始新安江模型计算
        Map<Object, Object> calc = XajModel.calc(xajData);
        List<Double> preQ = Convert.toList(Double.class, calc.get("preQ"));
        List<Double> netRain = Convert.toList(Double.class, calc.get("netRain"));
        List<String> tms = hypCalcDto.getTms();
        if (preQ.size() != netRain.size() || preQ.size() != tms.size() || netRain.size() != tms.size())
            throw new Exception("计算数据异常！");
//        // 预报水位
        List<Double> regulate = DataUtil.regulate(preQ, tms, hypCalcDto.getRscd());
        List<Double> preZ = DataUtil.waterBalance(preQ, regulate, tms, hypCalcDto.getRscd());
//        // 校正流量
//        List<Double> checkQ = DataUtil.check(1, tms, preQ, hypCalcDto.getRscd());
        List<XajResult> xajResults = new ArrayList<>();
        for (int i = 0; i < preQ.size(); i++) {
            XajResult xajResult = new XajResult();
            xajResult.setTm(tms.get(i));
            xajResult.setPreQ(preQ.get(i));
            xajResult.setNetRain(netRain.get(i));
            xajResult.setAreaRain(prList.get(i));
            // TODO: 2024/6/16 需要替换为真实的预测水位和校正流量
            xajResult.setPreZ(preZ.get(i));
            xajResult.setCheckQ(NumberUtil.round(preQ.get(i) + Math.random(), 2).doubleValue());
//            xajResult.setCheckQ(checkQ.get(i));
            xajResults.add(xajResult);
        }
        HashMap<Object, Object> returnMap = new HashMap<>();
        // 新安江模型计算结果
        returnMap.put("xajData", xajResults);
        // 统计预报信息
        Map<String, Object> totalDetail = DataUtil.getTotalDetail(xajResults);
        totalDetail.put("runoffNum", NumberUtil.round(Double.valueOf(calc.get("runoffNum").toString()), 2));
        returnMap.put("counts", totalDetail);
        return returnMap;
    }

    @Override
    public Map<Object, Object> contrast(ContrastDto contrastDto) {
        HashMap<Object, Object> map = new HashMap<>();
        Double totalRain = 0.0;
        // 查询新安江模型计算的数据
        HashMap<String, Object> map1 = new HashMap<>();
        HashMap<String, Object> map2 = new HashMap<>();
        for (String id : contrastDto.getIds()) {
            Plan plan = planService.getById(id);
            QueryWrapper<XajResult> xajResultQueryWrapper = new QueryWrapper<>();
            xajResultQueryWrapper.select("id", "tm", "check_q", "pre_q", "area_Rain")
                    .eq("plan_id", id).orderByAsc("tm");
            List<XajResult> xajResults = xajResultService.list(xajResultQueryWrapper);
            map1.put(plan.getPlanName(), xajResults);
            // 获取方案统计信息
            Map<String, Object> totalDetail = DataUtil.getTotalDetail(xajResults);
            totalRain = Double.valueOf(totalDetail.get("totalRain").toString());
            totalDetail.put("nash", plan.getNash());
            map2.put(plan.getPlanName(), totalDetail);
        }
        map.put("planData", map1);
        map.put("plantotalData", map2);
        // 查询水库实测数据
        QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
        rsvrRLasteQueryWrapper.select("id", "tm", "rz", "inq").eq("stcd", contrastDto.getRscd())
                .ge("tm", contrastDto.getStartTime()).le("tm", contrastDto.getEndTime())
                .apply("date_trunc('hour', tm) = tm").orderByAsc("tm");
        List<RsvrRLaste> rsvrRS = rsvrRLasteService.list(rsvrRLasteQueryWrapper);
        map.put("relData", rsvrRS);
        // 实测统计信息
        Double totalinQ = 0.0;
        for (int i = 0; i < rsvrRS.size(); i++) {
            if (i == rsvrRS.size() - 1) {
                totalinQ = totalinQ;
            } else {
                // 获取洪峰流量
                totalinQ = totalinQ + (rsvrRS.get(i).getInq() + rsvrRS.get(i + 1).getInq()) * 1800 / 10000;
            }
        }
        RsvrRLaste rsvrRLaste = rsvrRS.stream().sorted(Comparator.comparingDouble(RsvrRLaste::getInq).reversed())
                .findFirst()
                .orElse(null);
        // 获取洪峰流量
        Double floodMax = rsvrRLaste.getInq();
        // 获取峰现时间
        Date floodTime = rsvrRLaste.getTm();
        HashMap<Object, Object> relmap = new HashMap<>();
        relmap.put("totalRain", totalRain);
        relmap.put("floodMax", floodMax);
        relmap.put("totalpreFlood", totalinQ);
        relmap.put("floodTime", DateUtil.format(floodTime, "yyyy-MM-dd HH:mm:ss"));
        map.put("reltotalData", relmap);
        return map;
    }

    @Override
    public Map<Object, Object> getAutoData(String rscd) throws Exception {
        // 查询预报数据
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("rscd", rscd).eq("calc_type", "自动计算").eq("pre_type", "预报")
                .orderByDesc("create_time").last("limit 1");
        Plan plan = planService.getOne(planQueryWrapper);
        HashMap<Object, Object> map = new HashMap<>();
        if (BeanUtil.isNotEmpty(plan)) {
            QueryWrapper<XajResult> xajResultQueryWrapper = new QueryWrapper<>();
            xajResultQueryWrapper.select("id", "tm", "pre_q", "pre_z", "area_rain")
                    .eq("plan_id", plan.getId()).orderByAsc("tm");
            // 面雨量、预报水位
            List<XajResult> xajResults = xajResultService.list(xajResultQueryWrapper);
            // 查询统计信息
            Map<String, Object> totalDetail = DataUtil.getTotalDetail(xajResults);
            // 预测入库洪量
            Double totalpreFlood = Double.valueOf(totalDetail.get("totalpreFlood").toString());
            // 峰现时间
            String floodTime = totalDetail.get("floodTime").toString();
            // 获取水库实测水位
//            QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
//            rsvrRLasteQueryWrapper.select("id", "tm", "rz").eq("stcd", rscd)
//                    .ge("tm", DateUtil.offsetDay(plan.getStartTime(),-1)).le("tm", plan.getStartTime())
//                    .apply("date_trunc('hour', tm) = tm").orderByAsc("tm");
//            List<RsvrRLaste> rsvrRS = rsvrRLasteService.list(rsvrRLasteQueryWrapper);
            List<RsvrRLaste> rsvrRS = DataServiceUtil.getRsvrVoList(rscd, DateUtil.offsetDay(plan.getStartTime(), -1), plan.getStartTime(), 1);
            // 获取实时水位
//            QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper1 = new QueryWrapper<>();
//            rsvrRLasteQueryWrapper1.eq("stcd", rscd).orderByDesc("tm").last("limit 1");
//            Double rz = rsvrRLasteService.getOne(rsvrRLasteQueryWrapper1).getRz();
//            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//            List<RsvrRLaste> rsvrRS2 = DataServiceUtil.getRsvrVoList(rscd, DateUtil.offsetDay(DateUtil.parse(format), -2), DateUtil.offsetDay(plan.getStartTime(),1), 1);
            if (rsvrRS.size()!=0){
                Optional<Double> lastNonNullRz = rsvrRS.stream()
                        .map(RsvrRLaste::getRz) // 提取 rz 字段的值
                        .filter(rz -> rz != null) // 过滤掉 rz 为 null 的值
                        .reduce((first, second) -> second); // 获取最后一个值
                Double rz = lastNonNullRz.get();
                // 实时水位
                map.put("relZ", NumberUtil.round(rz, 2));
            }
            // 获取未来两小时降雨量
            Date startTime = DateUtil.parse(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:00:00")).toJdkDate();
            DateTime dateTime = DateUtil.offsetHour(startTime, 2);
            HashMap<Object, Object> areaRainfall = DataUtil.getpreAreaRainfall(rscd, startTime, dateTime, 1);
            List<Double> areaRain = Convert.toList(Double.class, areaRainfall.get("areaRain"));
//            Double hoursum = areaRain.stream().mapToDouble(Double::doubleValue).sum();
            // 降雨数据
            map.put("hoursum", NumberUtil.round(Double.valueOf(totalDetail.get("totalRain").toString()), 1));

            // 预测入库洪量
            map.put("totalpreFlood", NumberUtil.round(totalpreFlood, 2));
            // 入库峰现时间
            map.put("floodTime", floodTime);
            // 更新时间
            map.put("updateTime", DateUtil.format(plan.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            // 实测水位数据
            map.put("relData", rsvrRS);
            // 预报水位
            map.put("preData", xajResults);
            // 获取预警数据
            HashMap<Object, Object> data = prewarnService.getData(plan.getId());
            data.remove("xajData");
            data.remove("counts");
            map.put("warndata", data);
            // 获取实测面雨量
            HashMap<Object, Object> drpVoList = DataServiceUtil.getDrpVoList(rscd, DateUtil.offsetDay(plan.getStartTime(), -1), plan.getStartTime(), 1);
            map.put("relareaRain", drpVoList);

        }
//        String response;
//        // 判断redis缓存中是否存在key
//        if (caiyunredisTemplate.hasKey("weather_"+rscd)){
//            // 获取存在的值
//            response = caiyunredisTemplate.opsForValue().get("weather_" + rscd);
//        }else {
//            // 获取当前水库的预报消息
//            WrpRsrBsin wrpRsrBsin = rsrBsinService.lambdaQuery().eq(WrpRsrBsin::getRscd, rscd).one();
//            String url = "https://api.caiyunapi.com/v2.6/i7tXehBFkqTfZUae/"+wrpRsrBsin.getEslg()+","+wrpRsrBsin.getNrlt()+"/realtime?alert=true";
//            // 发送请求
//            response = HttpRequest.get(url).execute().body();
//            caiyunredisTemplate.opsForValue().set("weather_" + rscd, response, 60, TimeUnit.MINUTES);
//        }
//        // 解析JSON响应
//        JSONObject jsonObject = new JSONObject(response);
//        JSONArray content = jsonObject.getJSONObject("result").getJSONObject("alert").getJSONArray("content");
//        HashMap<Object, Object> map1 = new HashMap<>();
//        // 当前降雨描述
//        map1.put("updateTime",DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
//        // 天气状况
//        map1.put("skycon",jsonObject.getJSONObject("result").getJSONObject("realtime").getStr("skycon"));
//        //
//        if (content.size()>0){
//            for (Object o : content) {
//                JSONObject entries = new JSONObject(o);
//                map1.put("warn_title",entries.getStr("title"));
//                map1.put("warn_description",entries.getStr("description"));
//                map1.put("warn_source",entries.getStr("source"));
//            }
//        }
//        map.put("weatherPre",map1);
        return map;
    }

    /**
     * 获取预报气象数据
     *
     * @param rscd
     * @return
     */
    @Override
    public Map<Object, Object> getWeatherData(String rscd) {
        HashMap<Object, Object> map = new HashMap<>();
        String response;
        // 判断redis缓存中是否存在key
        if (caiyunredisTemplate.hasKey("weather_" + rscd)) {
            // 获取存在的值
            response = caiyunredisTemplate.opsForValue().get("weather_" + rscd);
        } else {
            // 获取当前水库的预报消息
            WrpRsrBsin wrpRsrBsin = rsrBsinService.lambdaQuery().eq(WrpRsrBsin::getRscd, rscd).one();
            String url = "https://api.caiyunapi.com/v2.6/i7tXehBFkqTfZUae/" + wrpRsrBsin.getEslg() + "," + wrpRsrBsin.getNrlt() + "/realtime?alert=true";
            // 发送请求
            response = HttpRequest.get(url).execute().body();
            caiyunredisTemplate.opsForValue().set("weather_" + rscd, response, 60, TimeUnit.MINUTES);
        }
        // 解析JSON响应
        JSONObject jsonObject = new JSONObject(response);
        JSONArray content = jsonObject.getJSONObject("result").getJSONObject("alert").getJSONArray("content");
        HashMap<Object, Object> map1 = new HashMap<>();
        // 当前降雨描述
        map1.put("updateTime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        // 天气状况
        map1.put("skycon", jsonObject.getJSONObject("result").getJSONObject("realtime").getStr("skycon"));
        //
        if (content.size() > 0) {
            for (Object o : content) {
                JSONObject entries = new JSONObject(o);
                map1.put("warn_title", entries.getStr("title"));
                map1.put("warn_description", entries.getStr("description"));
                map1.put("warn_source", entries.getStr("source"));
            }
        }
        map.put("weatherPre", map1);
        return map;
    }

    @Override
    public byte[] createBriefReportDocument(DocumentDto documentDto) throws IOException, InvalidFormatException {
        WordReport document = createDocument(documentDto);
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            document.write(baos);
            byte[] documentBytes = baos.toByteArray();

            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=document.docx");
            headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(documentBytes.length));

            return documentBytes;
        } catch (IOException e) {
            return new byte[0];
        }

    }

    @Override
    public AjaxResult orthostate(Double totaldrp, Integer numt, String type) {
        HashMap<String, Object> map = new HashMap<>();
        if (numt == 1){
            LinkedList<Double> drps = new LinkedList<>();


            List<String> tms = generateTimeSequence(numt);
            LinkedList<Double> doubles = new LinkedList<>();
/*            LocalDateTime now = LocalDateTime.now();

            // 获取当前整小时时间（分钟、秒、毫秒归零）
            LocalDateTime newdate = now.withMinute(0).withSecond(0).withNano(0);

            // 定义格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");*/

            drps.add(totaldrp);
            doubles.add(totaldrp);


            map.put("tms", tms);
            map.put("drps", drps);
            map.put("totaldrps", doubles);
            return AjaxResult.success(map);
        }

        switch (type) {
            case "正态分布":
                LinkedList<Double> drps = generateRainfall(totaldrp, numt, null, null);


                List<String> tms = generateTimeSequence(numt);
                LinkedList<Double> doubles = new LinkedList<>();
                Double sumdrps = 0.0;
                for (Double drp : drps) {
                    doubles.add(roundToOneDecimal1(sumdrps += drp));
                }
                createtms(numt, tms);

                map.put("tms", tms);
                map.put("drps", drps);
                map.put("totaldrps", doubles);
                break;
            case "芝加哥":
                drps = generateChicagoRainfall(totaldrp, numt, 0.3, 2.0, 2.0);


                tms = generateTimeSequence(numt);
                doubles = new LinkedList<>();
                //sumdrps = 0.0;
                BigDecimal sumdrps1 = BigDecimal.ZERO; // 使用 BigDecimal 初始化累加器

                for (Double drp : drps) {
                    //doubles.add(roundToOneDecimal1(sumdrps += drp));
                    // 将当前值转换为 BigDecimal，并累加到 sumdrps 中
                    sumdrps1 = sumdrps1.add(BigDecimal.valueOf(drp));

                    // 保留两位小数
                    sumdrps1 = sumdrps1.setScale(2, RoundingMode.HALF_UP);

                    // 将结果添加到列表中
                    doubles.add(sumdrps1.doubleValue());
                }
                createtms(numt, tms);
                map.put("tms", tms);
                map.put("drps", drps);
                map.put("totaldrps", doubles);
                break;

        }

        return AjaxResult.success(map);
    }

    /**
     * 芝加哥降雨
     *
     * @param totalRainfall
     * @param duration
     * @param peakPositionRatio
     * @param risingExponent
     * @param fallingExponent
     * @return
     */
    public static LinkedList<Double> generateChicagoRainfall(double totalRainfall, int duration,
                                                             double peakPositionRatio,
                                                             double risingExponent,
                                                             double fallingExponent) {
        // 参数校验
        if (duration <= 0) throw new IllegalArgumentException("Duration must be positive");
        if (peakPositionRatio < 0 || peakPositionRatio > 1) {
            throw new IllegalArgumentException("Peak position ratio must be between 0 and 1");
        }
        if (totalRainfall < 0) throw new IllegalArgumentException("Rainfall cannot be negative");

        double[] intensities = new double[duration];
        double peakTime = peakPositionRatio * duration;
        double sumIntensity = 0.0;

        // 计算强度分布
        for (int i = 0; i < duration; i++) {
            double intensity;
            if (peakTime == 0) { // 全下降段
                intensity = Math.pow((duration - i) / duration, fallingExponent);
            } else if (peakTime == duration) { // 全上升段
                intensity = Math.pow((double) i / duration, risingExponent);
            } else if (i <= peakTime) { // 上升段
                intensity = Math.pow(i / peakTime, risingExponent);
            } else { // 下降段
                intensity = Math.pow((duration - i) / (duration - peakTime), fallingExponent);
            }
            intensities[i] = intensity;
            sumIntensity += intensity;
        }

        // 创建一个 LinkedList 来存储最终雨量
        LinkedList<Double> rainfall = new LinkedList<>();
        if (sumIntensity == 0) return rainfall; // 避免除以零

        double sumRainfall = 0.0; // 用于累加已分配的雨量
        for (int i = 0; i < duration; i++) {
            // 计算当前雨量并保留两位小数
            double currentRainfall = BigDecimal.valueOf(totalRainfall * intensities[i] / sumIntensity)
                    .setScale(2, RoundingMode.HALF_UP)
                    .doubleValue();
            rainfall.add(currentRainfall);
            sumRainfall += currentRainfall;
        }

        // 调整误差，确保总和等于总雨量
        double error = totalRainfall - sumRainfall;
        if (error != 0 && !rainfall.isEmpty()) {
            // 将误差加到最后一个元素上
            int lastIndex = rainfall.size() - 1;
            double lastValue = rainfall.get(lastIndex);
            rainfall.set(lastIndex, BigDecimal.valueOf(lastValue + error)
                    .setScale(2, RoundingMode.HALF_UP)
                    .doubleValue());
        }

        return rainfall;
    }


    /**
     * 特殊处理小时为11:00:00  然后历时是12的时间序列
     *
     * @param numt
     * @param tms
     */
    private void createtms(Integer numt, List<String> tms) {
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String firstTimeStr = tms.get(0);

        LocalDateTime firstTime = LocalDateTime.parse(firstTimeStr, formatter);
        LocalDateTime targetTime = LocalDateTime.of(2025, 4, 18, 11, 0, 0); // 目标时间
        LocalDateTime atargetTime = LocalDateTime.of(2025, 4, 18, 15, 0, 0); // 目标时间

        if (firstTime.getHour() == targetTime.getHour() &&
                firstTime.getMinute() == targetTime.getMinute() &&
                firstTime.getSecond() == targetTime.getSecond() && numt == 12) {
            tms.remove(0); // 删除索引为 0 的元素（即第一个元素）
            String tm = tms.get(tms.size() - 1);
            // 将字符串解析为 LocalDateTime 对象
            LocalDateTime dateTime = LocalDateTime.parse(tm, formatter);

            // 增加一个小时
            LocalDateTime newDateTime = dateTime.plusHours(1);

            // 将新的时间格式化为字符串
            String newTm = newDateTime.format(formatter);
            tms.add(newTm);
        }

        if (firstTime.getHour() == atargetTime.getHour() &&
                firstTime.getMinute() == atargetTime.getMinute() &&
                firstTime.getSecond() == atargetTime.getSecond() && numt == 11) {
            tms.remove(0); // 删除索引为 0 的元素（即第一个元素）
            String tm = tms.get(tms.size() - 1);
            // 将字符串解析为 LocalDateTime 对象
            LocalDateTime dateTime = LocalDateTime.parse(tm, formatter);

            // 增加一个小时
            LocalDateTime newDateTime = dateTime.plusHours(1);

            // 将新的时间格式化为字符串
            String newTm = newDateTime.format(formatter);
            tms.add(newTm);
        }
    }

    public static List<String> generateTimeSequence(int numt) {
        // 获取当前时间的整点时间
        LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);

        // 定义时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 存储结果的时间序列
        List<String> timeSequence = new ArrayList<>();

        // 从当前时间开始递增，生成未来的时间点
        for (int i = 0; i < numt; i++) {
            // 计算未来的时间
            LocalDateTime futureHour = now.plusHours(i);
            // 格式化时间并添加到列表中
            timeSequence.add(futureHour.format(formatter));
        }

        return timeSequence;
    }


    /**
     * 正态分布降雨
     *
     * @param totalRain
     * @param durationHours
     * @param peakHour
     * @param stdDev
     * @return
     */
    public static LinkedList<Double> generateRainfall(double totalRain, int durationHours, Integer peakHour, Double stdDev) {
        // 参数默认值处理
        if (peakHour == null) peakHour = durationHours / 2;
        if (stdDev == null) stdDev = durationHours / 4.0;

        LinkedList<Double> rainfall = new LinkedList<>();
        double[] probabilities = new double[durationHours];
        double probSum = 0.0;

        // 1. 计算正态分布概率密度
        for (int t = 0; t < durationHours; t++) {
            double exponent = -0.5 * Math.pow((t - peakHour) / stdDev, 2);
            probabilities[t] = Math.exp(exponent);
            probSum += probabilities[t];
        }

        // 2. 归一化并分配降雨量 (保留一位小数)
        BigDecimal total = BigDecimal.ZERO;
        for (int t = 0; t < durationHours; t++) {
            double rain = probabilities[t] / probSum * totalRain;
            rain = roundToOneDecimal1(rain);
            rainfall.add(rain);
            total = total.add(BigDecimal.valueOf(rain));
        }

        // 3. 处理四舍五入导致的微小误差
        double diff = totalRain - total.doubleValue();
        if (diff != 0) {
            int lastIndex = durationHours - 1;
            double lastValue = rainfall.get(lastIndex) + diff;
            rainfall.set(lastIndex, roundToOneDecimal1(lastValue));
        }

        return rainfall;
    }

    // 四舍五入到一位小数
    private static double roundToOneDecimal1(double value) {
        return BigDecimal.valueOf(value).setScale(1, RoundingMode.HALF_UP).doubleValue();
    }

    private WordReport createDocument(DocumentDto documentDto) throws IOException, InvalidFormatException {
        try {
            String s = documentDto.getXajData();
            List<XajResult> xajData = JSONUtil.toList(s, XajResult.class);
            String startTime =xajData.get(0).getTm();
            String endTime = xajData.get(xajData.size()-1).getTm();

            QueryWrapper<WrpRsrBsin> wrpRsrBsinQueryWrapper = new QueryWrapper<>();
            wrpRsrBsinQueryWrapper.select("rsnm")
                    .eq("rscd", documentDto.getRscd());

            WrpRsrBsin one = wrpRsrBsinService.getOne(wrpRsrBsinQueryWrapper);
            WordReport wordReport = new WordReport();
            wordReport.setTitle(one.getRsnm() + "预报方案报告", "宋体", 20, true, "FF0000");
            wordReport.drawLine("FF0000");
            // 添加结论内容
            XajResult maxPreZ = xajData.stream()
                    .filter(x -> x.getPreZ() == xajData.stream().mapToDouble(XajResult::getPreZ).max().orElse(Double.NEGATIVE_INFINITY))
                    .findFirst()
                    .orElse(null);
            Double preZ = maxPreZ.getPreZ();
            // 判断是否超过汛限水位
            QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
            wrpRsrHychQueryWrapper.eq("rscd",documentDto.getRscd()).last("limit 1");
            Double mjflsscnwl = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper).getMjflsscnwl();
            String warn = (preZ > mjflsscnwl) ? "超过汛限水位，注意防范洪水风险。" : "暂无洪水风险。";

            String floodmaxTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(documentDto.getFloodTime());
            String preZmaxTime = maxPreZ.getTm();
            String conclusion = startTime+"至"+endTime+"，预报总降雨量将达到"+documentDto.getTotalRain()+"毫米，"+"预计在"+floodmaxTime
                    +"出现中最大洪峰流量"+documentDto.getFloodMax()+"m³/s，"+"预报总洪量为"+documentDto.getTotalpreFlood()+"万m³，"
                    +"预计在"+preZmaxTime+"出现水位最大值"+maxPreZ.getPreZ()+"米，"+warn;
            wordReport.addText("    "+conclusion,12);

            wordReport.nextLine();
            wordReport.addText("一、方案信息", 15, true);
            wordReport.addText("方案名称：" + documentDto.getPlanName(), 9);
            wordReport.addText("方案类型：" + documentDto.getCalcType(), 9);
            wordReport.addText("方案描述：" + documentDto.getPlanDesc(), 9);
            wordReport.nextLine();
            wordReport.addText("二、关键指标数据", 15, true);
            wordReport.addText("总降雨量：" + documentDto.getTotalRain()+"mm", 9);
            wordReport.addText("径流系数：" + documentDto.getRunoffNum(), 9);
            wordReport.addText("洪峰流量：" + documentDto.getFloodMax()+"m³/s", 9);
            wordReport.addText("预报总洪量：" + documentDto.getTotalpreFlood()+"万m³", 9);
            wordReport.addText("峰现时间：" + floodmaxTime, 9);
            wordReport.nextLine();
            wordReport.addText("三、方案过程数据", 15, true);
            // 绘制折线图
            MultipartFile chartFile = documentDto.getChartFile();
            wordReport.insertImage(convertMultipartFileToFile(chartFile));
            // 绘制表格
            List<String> head = new ArrayList<>(Arrays.asList("时间", "预报流量 (m³/s)", "预报水位 (m)","校正流量 (m³/s)","净雨 (mm)","面雨量 (mm)"));
            List<List<String>> datas = new ArrayList<>();
            for (XajResult xajDatum : xajData) {
                List<String> data = new ArrayList<>();
                data.add(xajDatum.getTm());
                data.add(Double.toString(xajDatum.getPreQ()));
                data.add(Double.toString(xajDatum.getPreZ()));
                // 判断是否有checkQ这个字段
                if (xajDatum.getCheckQ() == null) {
                    data.add("-");
                }else {
                    data.add(Double.toString(xajDatum.getCheckQ()));
                }
                data.add(Double.toString(xajDatum.getNetRain()));
                data.add(Double.toString(xajDatum.getAreaRain()));
                datas.add(data);
            }
            wordReport.addTable(datas,head);

            wordReport.addText(ParagraphAlignment.RIGHT,"数据来源："+documentDto.getSource(), "宋体",9,false);
            wordReport.addText(ParagraphAlignment.RIGHT,"方案制作时间："+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(documentDto.getMakeTime()),"宋体",9,false);

            return wordReport;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
        // 创建临时文件
        File file = File.createTempFile("temp-file", ".tmp");

        try (InputStream inputStream = multipartFile.getInputStream();
             FileOutputStream outputStream = new FileOutputStream(file)) {

            // 将 MultipartFile 的内容写入到临时文件
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        return file;
    }
}
